///////////////////////////////////////////////////////////////////////////////
//
//mmVector3.h
// 
// Author:
//      Mark Hobbs mark@hobsie.com
// 
// Copyright (c) 2010 Mark Hobbs
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef _MM_VECTOR3_H_
#define _MM_VECTOR3_H_

#include "mmDefines.h"
#include <math.h>

namespace MM
{

#ifdef _MSC_VER
__declspec(align(16)) class Vector3
#else
class Vector3
#endif
{
public:

	union
	{
		struct
		{
			float x,y,z;
		};
		float f[3];
	};

	float unused; // Padding to 16bytes
	
	inline Vector3();
	inline Vector3(float inputX, float inputY, float inputZ);
	inline Vector3(const Vector3 &vector);
	
	inline const Vector3 &operator = (const Vector3 &vector);
    inline Vector3 operator + (const Vector3 &vector);
    inline Vector3 operator - (const Vector3 &vector);
    inline Vector3 operator * (const float f);
    inline Vector3 operator / (const float f);
    inline Vector3 operator / (const Vector3 &vector);
    
    inline void operator += (const Vector3 &vector);
    inline void operator -= (const Vector3 &vector);
    inline void operator *= (const float f);
    inline void operator /= (const float f);
    
    inline float getMagnitude();
    inline float getSqrMagnitude();
    inline void  normalise();

#ifdef __GNUC__
} __attribute__ ((aligned(16)));
#else
}; // class Vector3
#endif

// Inline function definitions
inline Vector3::Vector3()
{
}
		
inline Vector3::Vector3(float inputX, float inputY, float inputZ)
{
	x = inputX;
	y = inputY;
	z = inputZ;
}

inline Vector3::Vector3(const Vector3 &vector)
{
	x = vector.x;
	y = vector.y;
	z = vector.z;
}

inline const Vector3& Vector3::operator = (const Vector3 &vector)
{
  x = vector.x;
  y = vector.y;
  z = vector.z;
  return *this;
}

inline Vector3 Vector3::operator + (const Vector3 &vector)
{
	Vector3 temp;
	temp.x = x + vector.x;
	temp.y = y + vector.y;
	temp.z = z + vector.z;
	return temp;
}

inline Vector3 Vector3::operator - (const Vector3 &vector)
{
	Vector3 temp;
	temp.x = x - vector.x;
	temp.y = y - vector.y;
	temp.z = z - vector.z;
	return temp;
}

inline Vector3 Vector3::operator * (const float f)
{
	Vector3 temp;
	temp.x = x * f;
	temp.y = y * f;
	temp.z = z * f;
	return temp;
}

inline Vector3 Vector3::operator / (const float f)
{
	Vector3 temp;
	float tempFloat = 1.0f / f;
	temp.x = x * tempFloat;
	temp.y = y * tempFloat;
	temp.z = z * tempFloat;
	return temp;
}

inline Vector3 Vector3::operator / (const Vector3 &vector)
{
	Vector3 temp;
	temp.x = x / vector.x;
	temp.y = y / vector.y;
	temp.z = z / vector.z;
	return temp;
}

inline void Vector3::operator += (const Vector3 &vector)
{
  	x += vector.x;
	y += vector.y;
	z += vector.z;
}

inline void Vector3::operator -= (const Vector3 &vector)
{
  	x -= vector.x;
	y -= vector.y;
	z -= vector.z;
}

inline void Vector3::operator *= (const float f)
{
  	x *= f;
	y *= f;
	z *= f;
}

inline void Vector3::operator /= (const float f)
{
	float tempFloat = 1.0f / f;
  	x *= tempFloat;
	y *= tempFloat;
	z *= tempFloat;
}

inline float Vector3::getMagnitude()
{
	return sqrtf(getSqrMagnitude());
}

inline float Vector3::getSqrMagnitude()
{
	return ((x * x)+(y * y)+(z * z));
}

inline void Vector3::normalise()
{
	float length = getMagnitude();
	
	if(length <= MM_MIN_VALUE)
		return;

	float tempFloat = length;
		
	x = x * tempFloat;
	y = y * tempFloat;
	z = z * tempFloat;
}
	
} // namespace MM

#endif // _MM_VECTOR3_H_
